package org.zoomdev.zoom.dao.impl;

import org.zoomdev.zoom.common.utils.NameCaseConverter;
import org.zoomdev.zoom.dao.Dao;
import org.zoomdev.zoom.dao.alias.NameMapping;
import org.zoomdev.zoom.dao.alias.NameMappingFactory;
import org.zoomdev.zoom.dao.alias.impl.CamelNameMapping;
import org.zoomdev.zoom.dao.driver.SqlDriver;
import org.zoomdev.zoom.dao.meta.ColumnMeta;
import org.zoomdev.zoom.dao.meta.TableMeta;

import java.util.HashMap;
import java.util.LinkedHashMap;

/**
 * 重命名相关策略
 */
final class RenameUtils {
    public static HashMap<String, ColumnRenameConfig> rename(Dao dao,
                                                             TableSource table) {

        TableMeta tableMeta = dao.getDbStructFactory().getTableMeta(table.table);

        NameMappingFactory factory = dao.getAliasPolicyFactory();
        NameMapping nameMapping = factory.create(getColumnNames(tableMeta));
        HashMap<String, ColumnRenameConfig> config = new LinkedHashMap<>();
        for (ColumnMeta columnMeta : tableMeta.getColumns()) {
            String fieldName = nameMapping.getMapping(columnMeta.getName());

            config.put(fieldName, new ColumnRenameConfig(
                    tableMeta,
                    columnMeta,
                    columnMeta.getName(),
                    columnMeta.getName(),
                    null,
                    fieldName
            ));
        }
        return config;

    }

    static String[] getColumnNames(TableMeta meta) {

        String[] names = new String[meta.getColumns().length];
        int index = 0;
        for (ColumnMeta columnMeta : meta.getColumns()) {
            names[index++] = columnMeta.getName();
        }
        return names;
    }

    public static HashMap<String, ColumnRenameConfig> rename(Dao dao, TableSource[] tables,
                                                             /**
                                                              * 用于Record模式，
                                                              * 字段名称为 table.column的形式
                                                              */
                                                             boolean dotStyle) {
        NameMappingFactory factory = dao.getAliasPolicyFactory();
        String[] tableNames = getTableNames(tables, factory);
        HashMap<String, ColumnRenameConfig> config = new LinkedHashMap<>();
        SqlDriver driver = dao.getDriver();
        boolean first = true;
        for (int i = 0; i < tables.length; ++i) {
            TableSource table = tables[i];
            TableMeta tableMeta = dao.getDbStructFactory().getTableMeta(table.table);
            String tableAliasName = tableNames[i];
            // 取出每一个表的重命名策略
            NameMapping columnNameMapping = getAliasPolicyForNames(factory, getColumnNames(tableMeta));
            for (ColumnMeta columnMeta : tableMeta.getColumns()) {
                String columnAliasName = columnNameMapping.getMapping(columnMeta.getName());
                //如果是第一个表，则直接使用字段名称，否则使用table.column的形式
                String fieldName = getFieldName(first, dotStyle, tableAliasName, columnAliasName);
                String asName = dotStyle ? getFieldName(first, false, tableAliasName, columnAliasName) : fieldName;

                String selectColumnName = String.format("%s.%s AS %s", tableAliasName,
                        driver.protectColumn(columnMeta.getName()),
                        driver.protectColumn(NameCaseConverter.toSnakeCase(asName) + "_")
                );

                String columnName = String.format("%s.%s", tableAliasName, columnMeta.getName());

                config.put(fieldName, new ColumnRenameConfig(
                        tableMeta,
                        columnMeta,
                        selectColumnName,
                        columnName,
                        tableAliasName,
                        columnAliasName
                ));
            }
            if (first) first = false;
        }
        return config;
    }

    private static String[] getTableNames(TableSource[] tables, NameMappingFactory factory) {
        String[] result = new String[tables.length];
        if (hasAlias(tables)) {
            for (int i = 0; i < tables.length; ++i) {
                TableSource t = tables[i];
                result[i] = t.alias != null ? t.alias : t.table;
            }
            return result;
        }
        return getOrgTableNames(tables);
//        String[] tableNames = getOrgTableNames(tables);
//        AliasPolicy tableAliasPolicy = getAliasPolicyForNames(generator.md, tableNames);
//
//        for (int i = 0; i < tables.length; ++i) {
//            String tableAliasName = tableAliasPolicy.getAlias(tables[i].table);
//            result[i] = tableAliasName;
//        }
//        return result;
    }

    private static NameMapping getAliasPolicyForNames(NameMappingFactory factory, String[] names) {
        NameMapping nameMapping = factory.create(names);
        if (nameMapping == null) {
            nameMapping = CamelNameMapping.DEFAULT;
        }
        return nameMapping;
    }

    private static String getFieldName(boolean first,
                                       /**
                                        * 用于Record模式，
                                        * 字段名称为 table.column的形式
                                        */
                                       boolean dotStyle,
                                       String tableAliasName,
                                       String columnAliasName) {
        if (first) {
            return columnAliasName;
        }

        if (dotStyle) {
            return tableAliasName + "." + columnAliasName;
        }

        return tableAliasName + NameCaseConverter.capitalizeFirstLetter(columnAliasName);
    }

    private static boolean hasAlias(TableSource[] tables) {
        for (TableSource s : tables) {
            if (s.alias != null) {
                return true;
            }
        }
        return false;
    }

    private static String[] getOrgTableNames(TableSource[] tables) {
        String[] tableNames = new String[tables.length];
        for (int i = 0; i < tables.length; ++i) {
            tableNames[i] = tables[i].table;
        }
        return tableNames;
    }

    static class ColumnRenameConfig {
        TableMeta tableMeta;
        ColumnMeta columnMeta;
        String selectColumnName;
        // 可能为 table.column 或者 column
        String columnName;

        String tableAlias;

        String columnAlias;

        public ColumnRenameConfig(TableMeta tableMeta,
                                  ColumnMeta columnMeta,
                                  String selectColumnName,
                                  String columnName,
                                  String tableAlias,
                                  String columnAlias) {
            this.tableMeta = tableMeta;
            this.columnMeta = columnMeta;
            this.selectColumnName = selectColumnName;
            this.columnName = columnName;
            this.tableAlias = tableAlias;
            this.columnAlias = columnAlias;
        }

        public boolean is(String field) {
            if (field.equalsIgnoreCase(columnName)) {
                return true;
            }
            if (field.equalsIgnoreCase(selectColumnName)) {
                return true;
            }
            if (field.equalsIgnoreCase(tableMeta.getName() + "." + columnMeta.getName())) {
                return true;
            }

            if (tableAlias != null) {
                if (field.equalsIgnoreCase(tableAlias + "." + columnMeta.getName())) {
                    return true;
                }

                if (columnAlias != null) {
                    return field.equalsIgnoreCase(tableAlias + "." + columnAlias);
                }
            }
            return false;
        }

        @Override
        public String toString() {
            return tableMeta.getName() + "." + columnMeta.getName();
        }
    }
}
